/* *
 *
 *  GUI generator for Stock tools
 *
 *  (c) 2009-2017 Sebastian Bochan
 *
 *  License: www.highcharts.com/license
 *
 *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
 *
 * */
"use strict";
import H from "../parts/Globals.js";
import U from "../parts/Utilities.js";
var extend = U.extend,
  isArray = U.isArray,
  pick = U.pick;
var addEvent = H.addEvent,
  createElement = H.createElement,
  fireEvent = H.fireEvent,
  getStyle = H.getStyle,
  merge = H.merge,
  css = H.css,
  win = H.win,
  DIV = "div",
  SPAN = "span",
  UL = "ul",
  LI = "li",
  PREFIX = "highcharts-",
  activeClass = PREFIX + "active";
H.setOptions({
  /**
   * @optionparent lang
   */
  lang: {
    /**
     * Configure the stockTools GUI titles(hints) in the chart. Requires
     * the `stock-tools.js` module to be loaded.
     *
     * @product highstock
     * @since   7.0.0
     */
    stockTools: {
      gui: {
        // Main buttons:
        simpleShapes: "Simple shapes",
        lines: "Lines",
        crookedLines: "Crooked lines",
        measure: "Measure",
        advanced: "Advanced",
        toggleAnnotations: "Toggle annotations",
        verticalLabels: "Vertical labels",
        flags: "Flags",
        zoomChange: "Zoom change",
        typeChange: "Type change",
        saveChart: "Save chart",
        indicators: "Indicators",
        currentPriceIndicator: "Current Price Indicators",
        // Other features:
        zoomX: "Zoom X",
        zoomY: "Zoom Y",
        zoomXY: "Zooom XY",
        fullScreen: "Fullscreen",
        typeOHLC: "OHLC",
        typeLine: "Line",
        typeCandlestick: "Candlestick",
        // Basic shapes:
        circle: "Circle",
        label: "Label",
        rectangle: "Rectangle",
        // Flags:
        flagCirclepin: "Flag circle",
        flagDiamondpin: "Flag diamond",
        flagSquarepin: "Flag square",
        flagSimplepin: "Flag simple",
        // Measures:
        measureXY: "Measure XY",
        measureX: "Measure X",
        measureY: "Measure Y",
        // Segment, ray and line:
        segment: "Segment",
        arrowSegment: "Arrow segment",
        ray: "Ray",
        arrowRay: "Arrow ray",
        line: "Line",
        arrowLine: "Arrow line",
        horizontalLine: "Horizontal line",
        verticalLine: "Vertical line",
        infinityLine: "Infinity line",
        // Crooked lines:
        crooked3: "Crooked 3 line",
        crooked5: "Crooked 5 line",
        elliott3: "Elliott 3 line",
        elliott5: "Elliott 5 line",
        // Counters:
        verticalCounter: "Vertical counter",
        verticalLabel: "Vertical label",
        verticalArrow: "Vertical arrow",
        // Advanced:
        fibonacci: "Fibonacci",
        pitchfork: "Pitchfork",
        parallelChannel: "Parallel channel",
      },
    },
    navigation: {
      popup: {
        // Annotations:
        circle: "Circle",
        rectangle: "Rectangle",
        label: "Label",
        segment: "Segment",
        arrowSegment: "Arrow segment",
        ray: "Ray",
        arrowRay: "Arrow ray",
        line: "Line",
        arrowLine: "Arrow line",
        horizontalLine: "Horizontal line",
        verticalLine: "Vertical line",
        crooked3: "Crooked 3 line",
        crooked5: "Crooked 5 line",
        elliott3: "Elliott 3 line",
        elliott5: "Elliott 5 line",
        verticalCounter: "Vertical counter",
        verticalLabel: "Vertical label",
        verticalArrow: "Vertical arrow",
        fibonacci: "Fibonacci",
        pitchfork: "Pitchfork",
        parallelChannel: "Parallel channel",
        infinityLine: "Infinity line",
        measure: "Measure",
        measureXY: "Measure XY",
        measureX: "Measure X",
        measureY: "Measure Y",
        // Flags:
        flags: "Flags",
        // GUI elements:
        addButton: "add",
        saveButton: "save",
        editButton: "edit",
        removeButton: "remove",
        series: "Series",
        volume: "Volume",
        connector: "Connector",
        // Field names:
        innerBackground: "Inner background",
        outerBackground: "Outer background",
        crosshairX: "Crosshair X",
        crosshairY: "Crosshair Y",
        tunnel: "Tunnel",
        background: "Background",
      },
    },
  },
  /**
   * Configure the stockTools gui strings in the chart. Requires the
   * [stockTools module]() to be loaded. For a description of the module
   * and information on its features, see [Highcharts StockTools]().
   *
   * @product highstock
   *
   * @sample stock/demo/stock-tools-gui Stock Tools GUI
   *
   * @sample stock/demo/stock-tools-custom-gui Stock Tools customized GUI
   *
   * @since        7.0.0
   * @optionparent stockTools
   */
  stockTools: {
    /**
     * Definitions of buttons in Stock Tools GUI.
     */
    gui: {
      /**
       * Path where Highcharts will look for icons. Change this to use
       * icons from a different server.
       *
       * Since 7.1.3 use [iconsURL](#navigation.iconsURL) for popup and
       * stock tools.
       *
       * @deprecated
       * @apioption stockTools.gui.iconsURL
       *
       */
      /**
       * Enable or disable the stockTools gui.
       */
      enabled: true,
      /**
       * A CSS class name to apply to the stocktools' div,
       * allowing unique CSS styling for each chart.
       */
      className: "highcharts-bindings-wrapper",
      /**
       * A CSS class name to apply to the container of buttons,
       * allowing unique CSS styling for each chart.
       */
      toolbarClassName: "stocktools-toolbar",
      /**
       * A collection of strings pointing to config options for the
       * toolbar items. Each name refers to unique key from definitions
       * object.
       *
       * @default [
       *   'indicators',
       *   'separator',
       *   'simpleShapes',
       *   'lines',
       *   'crookedLines',
       *   'measure',
       *   'advanced',
       *   'toggleAnnotations',
       *   'separator',
       *   'verticalLabels',
       *   'flags',
       *   'separator',
       *   'zoomChange',
       *   'fullScreen',
       *   'typeChange',
       *   'separator',
       *   'currentPriceIndicator',
       *   'saveChart'
       * ]
       */
      buttons: [
        "indicators",
        "separator",
        "simpleShapes",
        "lines",
        "crookedLines",
        "measure",
        "advanced",
        "toggleAnnotations",
        "separator",
        "verticalLabels",
        "flags",
        "separator",
        "zoomChange",
        "fullScreen",
        "typeChange",
        "separator",
        "currentPriceIndicator",
        "saveChart",
      ],
      /**
       * An options object of the buttons definitions. Each name refers to
       * unique key from buttons array.
       */
      definitions: {
        separator: {
          /**
           * A predefined background symbol for the button.
           */
          symbol: "separator.svg",
        },
        simpleShapes: {
          /**
           * A collection of strings pointing to config options for
           * the items.
           *
           * @type {array}
           * @default [
           *   'label',
           *   'circle',
           *   'rectangle'
           * ]
           *
           */
          items: ["label", "circle", "rectangle"],
          circle: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             *
             */
            symbol: "circle.svg",
          },
          rectangle: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             *
             */
            symbol: "rectangle.svg",
          },
          label: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             *
             */
            symbol: "label.svg",
          },
        },
        flags: {
          /**
           * A collection of strings pointing to config options for
           * the items.
           *
           * @type {array}
           * @default [
           *   'flagCirclepin',
           *   'flagDiamondpin',
           *   'flagSquarepin',
           *   'flagSimplepin'
           * ]
           *
           */
          items: [
            "flagCirclepin",
            "flagDiamondpin",
            "flagSquarepin",
            "flagSimplepin",
          ],
          flagSimplepin: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             *
             */
            symbol: "flag-basic.svg",
          },
          flagDiamondpin: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             *
             */
            symbol: "flag-diamond.svg",
          },
          flagSquarepin: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "flag-trapeze.svg",
          },
          flagCirclepin: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "flag-elipse.svg",
          },
        },
        lines: {
          /**
           * A collection of strings pointing to config options for
           * the items.
           *
           * @type {array}
           * @default [
           *   'segment',
           *   'arrowSegment',
           *   'ray',
           *   'arrowRay',
           *   'line',
           *   'arrowLine',
           *   'horizontalLine',
           *   'verticalLine'
           * ]
           */
          items: [
            "segment",
            "arrowSegment",
            "ray",
            "arrowRay",
            "line",
            "arrowLine",
            "horizontalLine",
            "verticalLine",
          ],
          segment: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "segment.svg",
          },
          arrowSegment: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "arrow-segment.svg",
          },
          ray: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "ray.svg",
          },
          arrowRay: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "arrow-ray.svg",
          },
          line: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "line.svg",
          },
          arrowLine: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "arrow-line.svg",
          },
          verticalLine: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "vertical-line.svg",
          },
          horizontalLine: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "horizontal-line.svg",
          },
        },
        crookedLines: {
          /**
           * A collection of strings pointing to config options for
           * the items.
           *
           * @type {array}
           * @default [
           *   'elliott3',
           *   'elliott5',
           *   'crooked3',
           *   'crooked5'
           * ]
           *
           */
          items: ["elliott3", "elliott5", "crooked3", "crooked5"],
          crooked3: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "crooked-3.svg",
          },
          crooked5: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "crooked-5.svg",
          },
          elliott3: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "elliott-3.svg",
          },
          elliott5: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "elliott-5.svg",
          },
        },
        verticalLabels: {
          /**
           * A collection of strings pointing to config options for
           * the items.
           *
           * @type {array}
           * @default [
           *   'verticalCounter',
           *   'verticalLabel',
           *   'verticalArrow'
           * ]
           */
          items: ["verticalCounter", "verticalLabel", "verticalArrow"],
          verticalCounter: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "vertical-counter.svg",
          },
          verticalLabel: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "vertical-label.svg",
          },
          verticalArrow: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "vertical-arrow.svg",
          },
        },
        advanced: {
          /**
           * A collection of strings pointing to config options for
           * the items.
           *
           * @type {array}
           * @default [
           *   'fibonacci',
           *   'pitchfork',
           *   'parallelChannel'
           * ]
           */
          items: ["fibonacci", "pitchfork", "parallelChannel"],
          pitchfork: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "pitchfork.svg",
          },
          fibonacci: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "fibonacci.svg",
          },
          parallelChannel: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "parallel-channel.svg",
          },
        },
        measure: {
          /**
           * A collection of strings pointing to config options for
           * the items.
           *
           * @type {array}
           * @default [
           *   'measureXY',
           *   'measureX',
           *   'measureY'
           * ]
           */
          items: ["measureXY", "measureX", "measureY"],
          measureX: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "measure-x.svg",
          },
          measureY: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "measure-y.svg",
          },
          measureXY: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "measure-xy.svg",
          },
        },
        toggleAnnotations: {
          /**
           * A predefined background symbol for the button.
           *
           * @type   {string}
           */
          symbol: "annotations-visible.svg",
        },
        currentPriceIndicator: {
          /**
           * A predefined background symbol for the button.
           *
           * @type   {string}
           */
          symbol: "current-price-show.svg",
        },
        indicators: {
          /**
           * A predefined background symbol for the button.
           *
           * @type   {string}
           */
          symbol: "indicators.svg",
        },
        zoomChange: {
          /**
           * A collection of strings pointing to config options for
           * the items.
           *
           * @type {array}
           * @default [
           *   'zoomX',
           *   'zoomY',
           *   'zoomXY'
           * ]
           */
          items: ["zoomX", "zoomY", "zoomXY"],
          zoomX: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "zoom-x.svg",
          },
          zoomY: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "zoom-y.svg",
          },
          zoomXY: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "zoom-xy.svg",
          },
        },
        typeChange: {
          /**
           * A collection of strings pointing to config options for
           * the items.
           *
           * @type {array}
           * @default [
           *   'typeOHLC',
           *   'typeLine',
           *   'typeCandlestick'
           * ]
           */
          items: ["typeOHLC", "typeLine", "typeCandlestick"],
          typeOHLC: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "series-ohlc.svg",
          },
          typeLine: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "series-line.svg",
          },
          typeCandlestick: {
            /**
             * A predefined background symbol for the button.
             *
             * @type   {string}
             */
            symbol: "series-candlestick.svg",
          },
        },
        fullScreen: {
          /**
           * A predefined background symbol for the button.
           *
           * @type   {string}
           */
          symbol: "fullscreen.svg",
        },
        saveChart: {
          /**
           * A predefined background symbol for the button.
           *
           * @type   {string}
           */
          symbol: "save-chart.svg",
        },
      },
    },
  },
});
/* eslint-disable no-invalid-this, valid-jsdoc */
// Run HTML generator
addEvent(H.Chart, "afterGetContainer", function () {
  this.setStockTools();
});
addEvent(H.Chart, "getMargins", function () {
  var listWrapper = this.stockTools && this.stockTools.listWrapper,
    offsetWidth =
      listWrapper &&
      (listWrapper.startWidth +
        H.getStyle(listWrapper, "padding-left") +
        H.getStyle(listWrapper, "padding-right") ||
        listWrapper.offsetWidth);
  if (offsetWidth && offsetWidth < this.plotWidth) {
    this.plotLeft += offsetWidth;
  }
});
addEvent(H.Chart, "destroy", function () {
  if (this.stockTools) {
    this.stockTools.destroy();
  }
});
addEvent(H.Chart, "redraw", function () {
  if (this.stockTools && this.stockTools.guiEnabled) {
    this.stockTools.redraw();
  }
});
/**
 * Toolbar Class
 * @private
 * @constructor
 * @param {Object} - options of toolbar
 * @param {Chart} - Reference to chart
 */
H.Toolbar = function (options, langOptions, chart) {
  this.chart = chart;
  this.options = options;
  this.lang = langOptions;
  // set url for icons.
  this.iconsURL = this.getIconsURL();
  this.guiEnabled = options.enabled;
  this.visible = pick(options.visible, true);
  this.placed = pick(options.placed, false);
  // General events collection which should be removed upon destroy/update:
  this.eventsToUnbind = [];
  if (this.guiEnabled) {
    this.createHTML();
    this.init();
    this.showHideNavigatorion();
  }
  fireEvent(this, "afterInit");
};
extend(H.Chart.prototype, {
  /**
   * Verify if Toolbar should be added.
   * @private
   * @param {Highcharts.StockToolsOptions} - chart options
   * @return {void}
   */
  setStockTools: function (options) {
    var chartOptions = this.options,
      lang = chartOptions.lang,
      guiOptions = merge(
        chartOptions.stockTools && chartOptions.stockTools.gui,
        options && options.gui
      ),
      langOptions = lang.stockTools && lang.stockTools.gui;
    this.stockTools = new H.Toolbar(guiOptions, langOptions, this);
    if (this.stockTools.guiEnabled) {
      this.isDirtyBox = true;
    }
  },
});
H.Toolbar.prototype = {
  /**
   * Initialize the toolbar. Create buttons and submenu for each option
   * defined in `stockTools.gui`.
   * @private
   */
  init: function () {
    var _self = this,
      lang = this.lang,
      guiOptions = this.options,
      toolbar = this.toolbar,
      addSubmenu = _self.addSubmenu,
      buttons = guiOptions.buttons,
      defs = guiOptions.definitions,
      allButtons = toolbar.childNodes,
      inIframe = this.inIframe(),
      button;
    // create buttons
    buttons.forEach(function (btnName) {
      button = _self.addButton(toolbar, defs, btnName, lang);
      if (inIframe && btnName === "fullScreen") {
        button.buttonWrapper.className += " " + PREFIX + "disabled-btn";
      }
      _self.eventsToUnbind.push(
        addEvent(button.buttonWrapper, "click", function () {
          _self.eraseActiveButtons(allButtons, button.buttonWrapper);
        })
      );
      if (isArray(defs[btnName].items)) {
        // create submenu buttons
        addSubmenu.call(_self, button, defs[btnName]);
      }
    });
  },
  /**
   * Create submenu (list of buttons) for the option. In example main button
   * is Line, in submenu will be buttons with types of lines.
   * @private
   * @param {Highcharts.Dictionary<Highcharts.HTMLDOMElement>}
   * button which has submenu
   * @param {Highcharts.StockToolsGuiDefinitionsButtonsOptions}
   * list of all buttons
   */
  addSubmenu: function (parentBtn, button) {
    var _self = this,
      submenuArrow = parentBtn.submenuArrow,
      buttonWrapper = parentBtn.buttonWrapper,
      buttonWidth = getStyle(buttonWrapper, "width"),
      wrapper = this.wrapper,
      menuWrapper = this.listWrapper,
      allButtons = this.toolbar.childNodes,
      topMargin = 0,
      submenuWrapper;
    // create submenu container
    this.submenu = submenuWrapper = createElement(
      UL,
      {
        className: PREFIX + "submenu-wrapper",
      },
      null,
      buttonWrapper
    );
    // create submenu buttons and select the first one
    this.addSubmenuItems(buttonWrapper, button);
    // show / hide submenu
    _self.eventsToUnbind.push(
      addEvent(submenuArrow, "click", function (e) {
        e.stopPropagation();
        // Erase active class on all other buttons
        _self.eraseActiveButtons(allButtons, buttonWrapper);
        // hide menu
        if (buttonWrapper.className.indexOf(PREFIX + "current") >= 0) {
          menuWrapper.style.width = menuWrapper.startWidth + "px";
          buttonWrapper.classList.remove(PREFIX + "current");
          submenuWrapper.style.display = "none";
        } else {
          // show menu
          // to calculate height of element
          submenuWrapper.style.display = "block";
          topMargin =
            submenuWrapper.offsetHeight - buttonWrapper.offsetHeight - 3;
          // calculate position of submenu in the box
          // if submenu is inside, reset top margin
          if (
            // cut on the bottom
            !(
              submenuWrapper.offsetHeight + buttonWrapper.offsetTop >
                wrapper.offsetHeight &&
              // cut on the top
              buttonWrapper.offsetTop > topMargin
            )
          ) {
            topMargin = 0;
          }
          // apply calculated styles
          css(submenuWrapper, {
            top: -topMargin + "px",
            left: buttonWidth + 3 + "px",
          });
          buttonWrapper.className += " " + PREFIX + "current";
          menuWrapper.startWidth = wrapper.offsetWidth;
          menuWrapper.style.width =
            menuWrapper.startWidth +
            H.getStyle(menuWrapper, "padding-left") +
            submenuWrapper.offsetWidth +
            3 +
            "px";
        }
      })
    );
  },
  /**
   * Create buttons in submenu
   * @private
   * @param {Highcharts.HTMLDOMElement}
   * button where submenu is placed
   * @param {Highcharts.StockToolsGuiDefinitionsButtonsOptions}
   * list of all buttons options
   *
   */
  addSubmenuItems: function (buttonWrapper, button) {
    var _self = this,
      submenuWrapper = this.submenu,
      lang = this.lang,
      menuWrapper = this.listWrapper,
      items = button.items,
      firstSubmenuItem,
      submenuBtn;
    // add items to submenu
    items.forEach(function (btnName) {
      // add buttons to submenu
      submenuBtn = _self.addButton(submenuWrapper, button, btnName, lang);
      _self.eventsToUnbind.push(
        addEvent(submenuBtn.mainButton, "click", function () {
          _self.switchSymbol(this, buttonWrapper, true);
          menuWrapper.style.width = menuWrapper.startWidth + "px";
          submenuWrapper.style.display = "none";
        })
      );
    });
    // select first submenu item
    firstSubmenuItem = submenuWrapper.querySelectorAll(
      "li > ." + PREFIX + "menu-item-btn"
    )[0];
    // replace current symbol, in main button, with submenu's button style
    _self.switchSymbol(firstSubmenuItem, false);
  },
  /*
   * Erase active class on all other buttons.
   *
   * @param {Array} - Array of HTML buttons
   * @param {HTMLDOMElement} - Current HTML button
   *
   */
  eraseActiveButtons: function (buttons, currentButton, submenuItems) {
    [].forEach.call(buttons, function (btn) {
      if (btn !== currentButton) {
        btn.classList.remove(PREFIX + "current");
        btn.classList.remove(PREFIX + "active");
        submenuItems = btn.querySelectorAll("." + PREFIX + "submenu-wrapper");
        // hide submenu
        if (submenuItems.length > 0) {
          submenuItems[0].style.display = "none";
        }
      }
    });
  },
  /**
   * Create single button. Consist of HTML elements `li`, `span`, and (if
   * exists) submenu container.
   * @private
   * @param {HTMLDOMElement} - HTML reference, where button should be added
   * @param {Object} - all options, by btnName refer to particular button
   * @param {String} - name of functionality mapped for specific class
   * @param {Object} - All titles, by btnName refer to particular button
   * @return {Object} - references to all created HTML elements
   */
  addButton: function (target, options, btnName, lang) {
    var btnOptions = options[btnName],
      items = btnOptions.items,
      classMapping = H.Toolbar.prototype.classMapping,
      userClassName = btnOptions.className || "",
      mainButton,
      submenuArrow,
      buttonWrapper;
    // main button wrapper
    buttonWrapper = createElement(
      LI,
      {
        className: pick(classMapping[btnName], "") + " " + userClassName,
        title: lang[btnName] || btnName,
      },
      null,
      target
    );
    // single button
    mainButton = createElement(
      SPAN,
      {
        className: PREFIX + "menu-item-btn",
      },
      null,
      buttonWrapper
    );
    // submenu
    if (items && items.length) {
      // arrow is a hook to show / hide submenu
      submenuArrow = createElement(
        SPAN,
        {
          className: PREFIX + "submenu-item-arrow " + PREFIX + "arrow-right",
        },
        null,
        buttonWrapper
      );
      submenuArrow.style["background-image"] =
        "url(" + this.iconsURL + "arrow-bottom.svg)";
    } else {
      mainButton.style["background-image"] =
        "url(" + this.iconsURL + btnOptions.symbol + ")";
    }
    return {
      buttonWrapper: buttonWrapper,
      mainButton: mainButton,
      submenuArrow: submenuArrow,
    };
  },
  /*
   * Create navigation's HTML elements: container and arrows.
   *
   */
  addNavigation: function () {
    var stockToolbar = this,
      wrapper = stockToolbar.wrapper;
    // arrow wrapper
    stockToolbar.arrowWrapper = createElement(DIV, {
      className: PREFIX + "arrow-wrapper",
    });
    stockToolbar.arrowUp = createElement(
      DIV,
      {
        className: PREFIX + "arrow-up",
      },
      null,
      stockToolbar.arrowWrapper
    );
    stockToolbar.arrowUp.style["background-image"] =
      "url(" + this.iconsURL + "arrow-right.svg)";
    stockToolbar.arrowDown = createElement(
      DIV,
      {
        className: PREFIX + "arrow-down",
      },
      null,
      stockToolbar.arrowWrapper
    );
    stockToolbar.arrowDown.style["background-image"] =
      "url(" + this.iconsURL + "arrow-right.svg)";
    wrapper.insertBefore(stockToolbar.arrowWrapper, wrapper.childNodes[0]);
    // attach scroll events
    stockToolbar.scrollButtons();
  },
  /*
   * Add events to navigation (two arrows) which allows user to scroll
   * top/down GUI buttons, if container's height is not enough.
   *
   */
  scrollButtons: function () {
    var targetY = 0,
      _self = this,
      wrapper = _self.wrapper,
      toolbar = _self.toolbar,
      step = 0.1 * wrapper.offsetHeight; // 0.1 = 10%
    _self.eventsToUnbind.push(
      addEvent(_self.arrowUp, "click", function () {
        if (targetY > 0) {
          targetY -= step;
          toolbar.style["margin-top"] = -targetY + "px";
        }
      })
    );
    _self.eventsToUnbind.push(
      addEvent(_self.arrowDown, "click", function () {
        if (wrapper.offsetHeight + targetY <= toolbar.offsetHeight + step) {
          targetY += step;
          toolbar.style["margin-top"] = -targetY + "px";
        }
      })
    );
  },
  /*
   * Create stockTools HTML main elements.
   *
   */
  createHTML: function () {
    var stockToolbar = this,
      chart = stockToolbar.chart,
      guiOptions = stockToolbar.options,
      container = chart.container,
      navigation = chart.options.navigation,
      bindingsClassName = navigation && navigation.bindingsClassName,
      listWrapper,
      toolbar,
      wrapper;
    // create main container
    stockToolbar.wrapper = wrapper = createElement(DIV, {
      className:
        PREFIX +
        "stocktools-wrapper " +
        guiOptions.className +
        " " +
        bindingsClassName,
    });
    container.parentNode.insertBefore(wrapper, container);
    // toolbar
    stockToolbar.toolbar = toolbar = createElement(UL, {
      className: PREFIX + "stocktools-toolbar " + guiOptions.toolbarClassName,
    });
    // add container for list of buttons
    stockToolbar.listWrapper = listWrapper = createElement(DIV, {
      className: PREFIX + "menu-wrapper",
    });
    wrapper.insertBefore(listWrapper, wrapper.childNodes[0]);
    listWrapper.insertBefore(toolbar, listWrapper.childNodes[0]);
    stockToolbar.showHideToolbar();
    // add navigation which allows user to scroll down / top GUI buttons
    stockToolbar.addNavigation();
  },
  /**
   * Function called in redraw verifies if the navigation should be visible.
   * @private
   */
  showHideNavigatorion: function () {
    // arrows
    // 50px space for arrows
    if (
      this.visible &&
      this.toolbar.offsetHeight > this.wrapper.offsetHeight - 50
    ) {
      this.arrowWrapper.style.display = "block";
    } else {
      // reset margin if whole toolbar is visible
      this.toolbar.style.marginTop = "0px";
      // hide arrows
      this.arrowWrapper.style.display = "none";
    }
  },
  /**
   * Create button which shows or hides GUI toolbar.
   * @private
   */
  showHideToolbar: function () {
    var stockToolbar = this,
      chart = this.chart,
      wrapper = stockToolbar.wrapper,
      toolbar = this.listWrapper,
      submenu = this.submenu,
      visible = this.visible,
      showhideBtn;
    // Show hide toolbar
    this.showhideBtn = showhideBtn = createElement(
      DIV,
      {
        className: PREFIX + "toggle-toolbar " + PREFIX + "arrow-left",
      },
      null,
      wrapper
    );
    showhideBtn.style["background-image"] =
      "url(" + this.iconsURL + "arrow-right.svg)";
    if (!visible) {
      // hide
      if (submenu) {
        submenu.style.display = "none";
      }
      showhideBtn.style.left = "0px";
      stockToolbar.visible = visible = false;
      toolbar.classList.add(PREFIX + "hide");
      showhideBtn.classList.toggle(PREFIX + "arrow-right");
      wrapper.style.height = showhideBtn.offsetHeight + "px";
    } else {
      wrapper.style.height = "100%";
      showhideBtn.style.top = H.getStyle(toolbar, "padding-top") + "px";
      showhideBtn.style.left =
        wrapper.offsetWidth + H.getStyle(toolbar, "padding-left") + "px";
    }
    // Toggle menu
    stockToolbar.eventsToUnbind.push(
      addEvent(showhideBtn, "click", function () {
        chart.update({
          stockTools: {
            gui: {
              visible: !visible,
              placed: true,
            },
          },
        });
      })
    );
  },
  /*
   * In main GUI button, replace icon and class with submenu button's
   * class / symbol.
   *
   * @param {HTMLDOMElement} - submenu button
   * @param {Boolean} - true or false
   *
   */
  switchSymbol: function (button, redraw) {
    var buttonWrapper = button.parentNode,
      buttonWrapperClass = buttonWrapper.classList.value,
      // main button in first level og GUI
      mainNavButton = buttonWrapper.parentNode.parentNode;
    // set class
    mainNavButton.className = "";
    if (buttonWrapperClass) {
      mainNavButton.classList.add(buttonWrapperClass.trim());
    }
    // set icon
    mainNavButton.querySelectorAll("." + PREFIX + "menu-item-btn")[0].style[
      "background-image"
    ] = button.style["background-image"];
    // set active class
    if (redraw) {
      this.selectButton(mainNavButton);
    }
  },
  /*
   * Set select state (active class) on button.
   *
   * @param {HTMLDOMElement} - button
   *
   */
  selectButton: function (button) {
    if (button.className.indexOf(activeClass) >= 0) {
      button.classList.remove(activeClass);
    } else {
      button.classList.add(activeClass);
    }
  },
  /*
   * Remove active class from all buttons except defined.
   *
   * @param {HTMLDOMElement} - button which should not be deactivated
   *
   */
  unselectAllButtons: function (button) {
    var activeButtons = button.parentNode.querySelectorAll("." + activeClass);
    [].forEach.call(activeButtons, function (activeBtn) {
      if (activeBtn !== button) {
        activeBtn.classList.remove(activeClass);
      }
    });
  },
  /*
   * Verify if chart is in iframe.
   *
   * @return {Object} - elements translations.
   */
  inIframe: function () {
    try {
      return win.self !== win.top;
    } catch (e) {
      return true;
    }
  },
  /*
   * Update GUI with given options.
   *
   * @param {Object} - general options for Stock Tools
   */
  update: function (options) {
    merge(true, this.chart.options.stockTools, options);
    this.destroy();
    this.chart.setStockTools(options);
    // If Stock Tools are updated, then bindings should be updated too:
    if (this.chart.navigationBindings) {
      this.chart.navigationBindings.update();
    }
  },
  /**
   * Destroy all HTML GUI elements.
   * @private
   */
  destroy: function () {
    var stockToolsDiv = this.wrapper,
      parent = stockToolsDiv && stockToolsDiv.parentNode;
    this.eventsToUnbind.forEach(function (unbinder) {
      unbinder();
    });
    // Remove the empty element
    if (parent) {
      parent.removeChild(stockToolsDiv);
    }
    // redraw
    this.chart.isDirtyBox = true;
    this.chart.redraw();
  },
  /**
   * Redraw, GUI requires to verify if the navigation should be visible.
   * @private
   */
  redraw: function () {
    this.showHideNavigatorion();
  },
  getIconsURL: function () {
    return (
      this.chart.options.navigation.iconsURL ||
      this.options.iconsURL ||
      "https://code.highcharts.com/8.0.0/gfx/stock-icons/"
    );
  },
  /**
   * Mapping JSON fields to CSS classes.
   * @private
   */
  classMapping: {
    circle: PREFIX + "circle-annotation",
    rectangle: PREFIX + "rectangle-annotation",
    label: PREFIX + "label-annotation",
    segment: PREFIX + "segment",
    arrowSegment: PREFIX + "arrow-segment",
    ray: PREFIX + "ray",
    arrowRay: PREFIX + "arrow-ray",
    line: PREFIX + "infinity-line",
    arrowLine: PREFIX + "arrow-infinity-line",
    verticalLine: PREFIX + "vertical-line",
    horizontalLine: PREFIX + "horizontal-line",
    crooked3: PREFIX + "crooked3",
    crooked5: PREFIX + "crooked5",
    elliott3: PREFIX + "elliott3",
    elliott5: PREFIX + "elliott5",
    pitchfork: PREFIX + "pitchfork",
    fibonacci: PREFIX + "fibonacci",
    parallelChannel: PREFIX + "parallel-channel",
    measureX: PREFIX + "measure-x",
    measureY: PREFIX + "measure-y",
    measureXY: PREFIX + "measure-xy",
    verticalCounter: PREFIX + "vertical-counter",
    verticalLabel: PREFIX + "vertical-label",
    verticalArrow: PREFIX + "vertical-arrow",
    currentPriceIndicator: PREFIX + "current-price-indicator",
    indicators: PREFIX + "indicators",
    flagCirclepin: PREFIX + "flag-circlepin",
    flagDiamondpin: PREFIX + "flag-diamondpin",
    flagSquarepin: PREFIX + "flag-squarepin",
    flagSimplepin: PREFIX + "flag-simplepin",
    zoomX: PREFIX + "zoom-x",
    zoomY: PREFIX + "zoom-y",
    zoomXY: PREFIX + "zoom-xy",
    typeLine: PREFIX + "series-type-line",
    typeOHLC: PREFIX + "series-type-ohlc",
    typeCandlestick: PREFIX + "series-type-candlestick",
    fullScreen: PREFIX + "full-screen",
    toggleAnnotations: PREFIX + "toggle-annotations",
    saveChart: PREFIX + "save-chart",
    separator: PREFIX + "separator",
  },
};
// Comunication with bindings:
addEvent(H.NavigationBindings, "selectButton", function (event) {
  var button = event.button,
    className = PREFIX + "submenu-wrapper",
    gui = this.chart.stockTools;
  if (gui && gui.guiEnabled) {
    // Unslect other active buttons
    gui.unselectAllButtons(event.button);
    // If clicked on a submenu, select state for it's parent
    if (button.parentNode.className.indexOf(className) >= 0) {
      button = button.parentNode.parentNode;
    }
    // Set active class on the current button
    gui.selectButton(button);
  }
});
addEvent(H.NavigationBindings, "deselectButton", function (event) {
  var button = event.button,
    className = PREFIX + "submenu-wrapper",
    gui = this.chart.stockTools;
  if (gui && gui.guiEnabled) {
    // If deselecting a button from a submenu, select state for it's parent
    if (button.parentNode.className.indexOf(className) >= 0) {
      button = button.parentNode.parentNode;
    }
    gui.selectButton(button);
  }
});
